﻿package base
{
    import com.dusk.game.Logger;
    import com.dusk.tool.DataBase;
    import com.dusk.tool.HitTest;
    import com.dusk.util.ArrayUtil;
    import com.dusk.util.BitmapUtil;
    import com.game.data.vo.HitResultVO;
    import com.game.data.vo.HitVO;
    import com.game.engine.phys.Vector2D;
    import com.game.manager.AnimationManager;
    import com.game.view.IAnimation;
    import com.game.view.display.AnimationClip;
    import com.game.view.display.AnimationLoopType;
    
    import flash.display.BitmapData;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    
    public class BaseBullet extends BaseObject
    {
        private var _bmd:BitmapData;
        
        public var hitVO:HitVO;
        public var isDisabled:Boolean = false;//设置为True后将不会进行攻击判断
        
        protected var hurt:int = 1;
        protected var scale:Point;
        protected var direct:int = 1;//1为向右，-1为向左
        protected var owner:BaseObject;//发射者
        protected var clip:AnimationClip;//动画
        protected var clipOffset:Point;//动画偏移
        protected var bulletName:String;//资源名称
        protected var hitTimeMap:DataBase;//目标被打事件记录
        
        protected var isAutoDirect:Boolean = false;//自动根据主人获取方向
        protected var isAutoCollideArea:Boolean = true;//自动获取碰撞区域
        
        protected var hitCount:int = 0;//击中次数
        protected var destroyInCount:int = -1;//运动多少帧后销毁
        
        protected var isDestroyWhenOwnerHurt:Boolean = false;//当主人受伤时是否销毁
        protected var isDestroyWhenLastFrame:Boolean = true;//当动画结束时是否销毁
        protected var isDestroyWhenReachMaxHitCount:Boolean = true;//当到达最大的攻击值时是否销毁
        
        protected var funcWhenHitWall:Function = null;
        protected var funcWhenHitTarget:Function = null;
        protected var funcWhenDestroy:Function = null;
        protected var funcWhenEnterFrame:Function = null;
        
        protected var funcWhenInCount:Array = [];//延时执行函数
        protected var funcInCountTimer:Array = [];//延时执行定时器
        
        
        public function BaseBullet(sourceName:String = "")
        {
            super();
            gravity = 0;
            velocity = Vector2D.zero;
            scale = new Point(1, 1);
            clipOffset = new Point(0,0);
            hitTimeMap = new DataBase();
            hitTimeMap.setDefaultValue(int.MIN_VALUE / 2);
            if (sourceName) setSourceName(sourceName);
        }
        
        public function setSourceName(name:String):void
        {
            bulletName = name;
            clip = AnimationManager.getAnimationClip(name);
            clip.loopType = AnimationLoopType.RESET_WHEN_END;
            addChild(clip);
        }
        
        public function setClip(c:AnimationClip):void
        {
            clip = c;
            clip.loopType = AnimationLoopType.RESET_WHEN_END;
            addChild(clip);
        }
        
        public function setIsDestroyWhenLastFrame(bool:Boolean = true):void
        {
            isDestroyWhenLastFrame = bool;
        }
        
        public function setIsDestroyWhenOwnerHurt(bool:Boolean = false):void
        {
            isDestroyWhenOwnerHurt = bool;
        }
        
        public function setIsDestroyWhenReachMaxHitCount(bool:Boolean = true):void
        {
            isDestroyWhenReachMaxHitCount = bool;
        }
        
        /**
         * 设置撞击墙壁后执行的逻辑
         * @param func 目标逻辑
         */
        public function setFuncWhenHitWall(func:Function):void
        {
            funcWhenHitWall = func;
        }
        
        /**
         * 设置打击到敌人后执行的逻辑
         * @param func 目标逻辑
         */
        public function setFuncWhenHitTarget(func:Function):void
        {
            funcWhenHitTarget = func;
        }
        
        protected function checkAttack():void
        {
            var realOwner:BaseObject = owner;
            var target:Array = null;
            if (!owner || !hitVO)
            {
                Logger.log("无主子弹和无配置子弹不参与碰撞!");
                return;
            }
            if(owner is BaseSummon)
            {
                realOwner = (owner as BaseSummon).getOwner();
            }
            if (realOwner is BaseHero || realOwner is BasePet)
            {
                target = gc.pWorld.getMonsterArray();
            }
            else
            {
                target = gc.team.getHeroAndPetArray();
            }
            for each(var i:BaseObject in target)
            {
                if (hitCount >= hitVO.maxHitCount)
                {
                    //到达最大攻击次数不继续判断碰撞
                    break;
                }
                if (_framer - hitTimeMap[i.gameObjectId] >= hitVO.hitInterval)
                {
                    //第一步判断攻击间隔成功，没有初始化的id默认参数为int.MIN_VALUE / 2
                    if (i.checkCollideRect(getCollideArea()))
                    {
                        //第二步判断当前子弹的碰撞区域和目标碰撞区域是重合的
                        //regionBullet主推，因为regionBullet碰撞使用collideBox，不会进行像素级碰撞
                        //自动碰撞一般用来偷懒，省去了测绘碰撞区大小的麻烦
                        if(isAutoCollideArea)
                        {
                            //第三步如果开启了自动碰撞，就会进行像素级碰撞，例如一个斜的三角形的碰撞区域就不会被判定为矩形碰撞框
                            //但是这里有一个重复步骤，在上一步中计算了当前图像的最小不透明区域，在进行复杂碰撞的时候会再次进行计算
                            if(!HitTest.complexHitTestObject(this,i.getCollideSprite()))
                            {
                                continue;
                            }
                        }
                        var result:HitResultVO = i.beHit(this, realOwner);
                        if(!result.success)
                        {
                            if(result.isMiss) hitTimeMap[i.gameObjectId] = _framer;
                            continue;
                        }
                        realOwner.hit(this,i,result);
                        if (funcWhenHitTarget) funcWhenHitTarget(this);
                        hitCount++;
                        hitTimeMap[i.gameObjectId] = _framer;
                    }
                }
            }
            if(funcInCountTimer.length > 0)
            {
                for (var idx:int = 0;idx < funcInCountTimer.length;idx++)
                {
                    funcInCountTimer[idx]--;
                    if(funcInCountTimer[idx] <= 0)
                    {
                        funcInCountTimer.splice(idx, 1);
                        funcWhenInCount[idx](this);
                        funcWhenInCount.splice(idx, 1);
                        idx--;
                    }
                }
            }
            if (isDestroyWhenReachMaxHitCount && hitCount >= hitVO.maxHitCount)
            {
                destroy();
            }
        }
        
        public function setScale(x:Number = 1, y:Number = 1):void
        {
            scaleX = x;
            scaleY = y;
            scale = new Point(x, y);
        }
        
        /**
         * 调用后子弹不参与攻击碰撞、墙体碰撞
         * 但是会进行动画渲染、每帧回调、定时销毁
         */
        public function setDisable():void
        {
            isDisabled = true;
        }
        
        public function setEnable():void
        {
            isDisabled = false;
        }
        
        /**
         * 设置动作，设置后会从攻击表中获取攻击数据，包括击退、僵直等等
         */
        override public function setAction(act:String):void
        {
            curAction = act;
            hitVO = gc.configManager.attackDataProxy.getHitVoById(act);
        }
        
        public function setFuncWhenDestroy(func:Function):void
        {
            funcWhenDestroy = func;
        }
        
        public function setFuncWhenEnterFrame(func:Function):void
        {
            funcWhenEnterFrame = func;
        }
        
        public function setOwner(o:BaseObject):void
        {
            owner = o;
        }
        
        public function getOwner():BaseObject
        {
            return owner;
        }
        
        /**
         * 设置伤害，伤害在beHit函数会进行重新计算
         */
        public function setHurt(value:int = 0):void
        {
            hurt = value;
        }
        
        public function getHurt():int
        {
            return hurt;
        }
        
        /**
         * direct会影响击退方向，同时改变此显示对象的方向
         * @param value 1为向右，-1为向左，传入角色方向即可
         */
        public function setDirect(value:int):void
        {
            direct = value;
            scaleX = direct * scale.x;
            scaleY = scale.y;
        }
        
        public function getDirect():int
        {
            return direct;
        }
        
        public function setAutoDirect(isAuto:Boolean = false):void
        {
            isAutoDirect = isAuto;
        }
        
        public function setFuncWhenInCount(func:Function, frame:int):void
        {
            funcWhenInCount.push(func);
            funcInCountTimer.push(frame);
        }
        
        public function setDestroyInCount(frame:uint):void
        {
            destroyInCount = frame;
            isDestroyWhenLastFrame = false;
        }
        
        public function getFrameLeft():uint
        {
            if (clip)
            {
                return clip.frameLeft;
            }
            return 0;
        }
        
        public function setClipOffset(x:Number = 0, y:Number = 0):void
        {
            clipOffset = new Point(x, y);
        }
        
        /**
         * 此API只有在懒得去改动画了才调用，正常情况翻转子弹调用setDirect即可
         */
        public function flipClip():void
        {
            clip.scaleX *= -1;
        }
        
        public function getBulletName():String
        {
            return bulletName;
        }
        
        public function getClip():IAnimation
        {
            return clip;
        }
        
        override public function getCollideArea():Rectangle
        {
            if (!isAutoCollideArea)
            {
                if (!collideBox)
                {
                    collideBox = new Rectangle(0, 0, 0, 0);
                }
                var rect:Rectangle = collideBox.clone();
                rect.offset(x, y);
                return rect;
            }
            if(width == 0 || height == 0)
            {
                return new Rectangle();
            }
            _bmd = new BitmapData(width, height, true, 0);
            _bmd.draw(this, null, null, null, null, false);
            var opaqueRect:Rectangle = BitmapUtil.getOpaqueRegion(_bmd);
            collideBox = getBounds(parent);
            collideBox.offset(opaqueRect.x, opaqueRect.y);
            _bmd.dispose();
            return collideBox;
        }
        
        public function setCollideArea(x:Number = 0, y:Number = 0, w:Number = 0, h:Number = 0):void
        {
            if (x == 0 && y == 0 && w == 0 && h == 0)
            {
                isAutoCollideArea = true;
            }
            //修正参数，当w or h < 0时，无法正确参与碰撞
            if(w < 0)
            {
                if(x >= 0)
                {
                    x += w;
                    w *= -1;
                }
                else
                {
                    x = w - x;
                    w *= -1;
                }
            }
            if(h < 0)
            {
                if(y >= 0)
                {
                    y += h;
                    h *= -1;
                }
                else
                {
                    y = h - y;
                    h *= -1;
                }
            }
            isAutoCollideArea = false;
            collideBox = new Rectangle(x, y, w, h);
        }
        
        override public function render(ratio:Number = 1):void
        {
            updatePosition(ratio);
            if(isAutoDirect)
            {
                setDirect(owner.getBBDC().getDirect());
            }
        }
        
        override public function renderAnimate():void
        {
            _framer++;
            if(clip)
            {
                clip.x = clipOffset.x;
                clip.y = clipOffset.y;
                clip.renderAnimate();
            }
            if (funcWhenEnterFrame)
            {
                funcWhenEnterFrame(this);
            }
            if (isDestroyWhenLastFrame && clip.frameLeft == 0)
            {
                destroy();
                return;
            }
            if (isDestroyWhenOwnerHurt && owner.curAction == "hurt")
            {
                destroy();
                return;
            }
            if (destroyInCount == _framer)
            {
                destroy();
                return;
            }
            if (isDisabled)
            {
                return;
            }
            checkAttack();
            checkHitWall();
        }
        
        private function checkHitWall():void
        {
            if (funcWhenHitWall != null)
            {
                for each(var wall:BaseTerrain in gc.pWorld.getTerrainArray())
                {
                    if (wall.width >= 800 && HitTest.complexHitTestObject(this, wall))
                    {
                        funcWhenHitWall(this);
                        destroy();
                        break;
                    }
                }
            }
        }
        
        override public function destroy():void
        {
            if (funcWhenDestroy != null)
            {
                funcWhenDestroy(this);
            }
            if (funcWhenEnterFrame != null)
            {
                funcWhenEnterFrame = null;
            }
            funcInCountTimer = [];
            ArrayUtil.removeAllElement(funcWhenInCount);
            isReadyToDestroy = true;
            if(clip)
            {
                clip.removeFromParent();
                clip = null;
            }
            removeFromParent();
            owner = null;
        }
    }
}
